name = '2015-12-14-geopandas_folium'
title = "Plotting a GeoDataFrame with folium"
%matplotlib inline
import os
from datetime import datetime
from IPython.core.display import HTML
import warnings
warnings.simplefilter("ignore")
hour = datetime.utcnow().strftime('%H:%M')
comments="true"
date = '-'.join(name.split('-')[:3])
slug = '-'.join(name.split('-')[3:])
metadata = dict(title=title,
date=date,
hour=hour,
comments=comments,
slug=slug,
name=name)
markdown = """Title: {title}
date: {date} {hour}
comments: {comments}
slug: {slug}
{{% notebook {name}.ipynb cells[2:] %}}
""".format(**metadata)
content = os.path.abspath(os.path.join(os.getcwd(),
os.pardir,
os.pardir,
'{}.md'.format(name)))
with open('{}'.format(content), 'w') as f:
f.writelines(markdown)
The visualization of thematic maps can get very messy very quick when there are many points to plot display.
In this post we will plot data from shapefile in the most visually efficient way possible.
Let's open our shapefiles with geopandas. (GeoPandas makes our task easy and that will be clear in a moment.)
import geopandas
path = './data/{}'.format
bus = geopandas.GeoDataFrame.from_file(path('metro_bus.shp'))
metro = geopandas.GeoDataFrame.from_file(path('Metro_Station_Entrances_District.shp'))
We need to know the Coordinate Reference System (CRS) of the data.
That information is stored in the .crs property and we can use pyepsg to get more information about it.
import pyepsg
pyepsg.get(metro.crs['init'].split(':')[1])
In order to plot our data we need to make sure that we are in a geographic coordinate system and create a GeoJSON object out of the GeoDataFrame.
Luckily, geopandas makes that extremely easy with the to_crs() method and, chained with the to_json(), we have an object ready for plotting with just one line.
gjson = metro.to_crs(epsg='4326').to_json()
import folium
mapa = folium.Map([38.904722, -77.016389],
zoom_start=11,
tiles='cartodbpositron')
points = folium.features.GeoJson(gjson)
mapa.add_children(points)
mapa
It is very hard to make sense of what we are plotting. The information is cluttered and has no description.
To make it better we can add more information as rich HTML popups.
And to reduced the clutter we can use the plugin MarkerCluster.
Since we have to groups of data to plot we can also use FeatureGroup to turn on/off the display of a specific group.
table = """
<!DOCTYPE html>
<html>
<head>
<style>
table {{
width:100%;
}}
table, th, td {{
border: 1px solid black;
border-collapse: collapse;
}}
th, td {{
padding: 5px;
text-align: left;
}}
table#t01 tr:nth-child(odd) {{
background-color: #eee;
}}
table#t01 tr:nth-child(even) {{
background-color:#fff;
}}
</style>
</head>
<body>
<table id="t01">
<tr>
<td>Type</td>
<td>{}</td>
</tr>
<tr>
<td>Name</td>
<td>{}</td>
</tr>
<tr>
<td>Entrance</td>
<td>{}</td>
</tr>
</table>
</body>
</html>
""".format
mapa = folium.Map([38.904722, -77.016389],
zoom_start=11,
tiles='cartodbpositron')
from folium.plugins import MarkerCluster
width, height = 310,110
popups, locations = [], []
for idx, row in metro.iterrows():
locations.append([row['geometry'].y, row['geometry'].x])
name = row['NAME']
entrance = row['EXIT_TO_ST']
iframe = folium.IFrame(table('Metro Stations', name, entrance), width=width, height=height)
popups.append(iframe)
h = folium.FeatureGroup(name='Metro Stations')
h.add_children(MarkerCluster(locations=locations, popups=popups))
mapa.add_children(h)
popups, locations = [], []
for idx, row in bus.iterrows():
locations.append([row['LATITUDE'], row['LONGITUDE']])
cross_st = row['AT_STR']
route_st = row['ON_STR']
iframe = folium.IFrame(table('DC Buses', route_st, cross_st), width=width, height=height)
popups.append(iframe)
t = folium.FeatureGroup(name='Buses')
t.add_children(MarkerCluster(locations=locations, popups=popups))
mapa.add_children(t)
mapa.add_children(folium.LayerControl())
mapa
This notebook was borrowed and slightly modified from Felipe Fernandez of python4oceanographers. The original can be found here https://nbviewer.ipython.org/url/ocefpaf.github.com/python4oceanographers/downloads/notebooks/2015-12-14-geopandas_folium.ipynb